/*
 * Copyright (C) 2006 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.dalongxin.work.utils;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.DownloadManager;
import android.content.ContentUris;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.widget.Toast;

import com.andview.refreshview.utils.LogUtils;
import com.dalongxin.work.BaseApplication;
import com.dalongxin.work.Constants;
import com.dalongxin.work.R;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.regex.Pattern;


/**
 * Tools for managing files.  Not for public consumption.
 * @hide
 */
public class FileUtils
{
    public static final int S_IRWXU = 00700;
    public static final int S_IRUSR = 00400;
    public static final int S_IWUSR = 00200;
    public static final int S_IXUSR = 00100;

    public static final int S_IRWXG = 00070;
    public static final int S_IRGRP = 00040;
    public static final int S_IWGRP = 00020;
    public static final int S_IXGRP = 00010;

    public static final int S_IRWXO = 00007;
    public static final int S_IROTH = 00004;
    public static final int S_IWOTH = 00002;
    public static final int S_IXOTH = 00001;
    
    
    /**
     * File status information. This class maps directly to the POSIX stat structure.
     * @hide
     */
    public static final class FileStatus {
        public int dev;
        public int ino;
        public int mode;
        public int nlink;
        public int uid;
        public int gid;
        public int rdev;
        public long size;
        public int blksize;
        public long blocks;
        public long atime;
        public long mtime;
        public long ctime;
    }
    
    /**
     * Perform an fsync on the given FileOutputStream.  The stream at this
     * point must be flushed but not yet closed.
     */
    public static boolean sync(FileOutputStream stream) {
        try {
            if (stream != null) {
                stream.getFD().sync();
            }
            return true;
        } catch (IOException e) {
        }
        return false;
    }

    // copy a file from srcFile to destFile, return true if succeed, return
    // false if fail
    public static boolean copyFile(File srcFile, File destFile) {
        boolean result = false;
        try {
            InputStream in = new FileInputStream(srcFile);
            try {
                result = copyToFile(in, destFile);
            } finally  {
                in.close();
            }
        } catch (IOException e) {
            result = false;
        }
        return result;
    }
    
    /**
     * Copy data from a source stream to destFile.
     * Return true if succeed, return false if failed.
     */
    public static boolean copyToFile(InputStream inputStream, File destFile) {
        try {
            if (destFile.exists()) {
                destFile.delete();
            }
            FileOutputStream out = new FileOutputStream(destFile);
            try {
                byte[] buffer = new byte[4096];
                int bytesRead;
                while ((bytesRead = inputStream.read(buffer)) >= 0) {
                    out.write(buffer, 0, bytesRead);
                }
            } finally {
                out.flush();
                try {
                    out.getFD().sync();
                } catch (IOException e) {
                }
                out.close();
            }
            return true;
        } catch (IOException e) {
            return false;
        }
    }

    /**
     * Read a text file into a String, optionally limiting the length.
     * @param file to read (will not seek, so things like /proc files are OK)
     * @param max length (positive for head, negative of tail, 0 for no limit)
     * @param ellipsis to add of the file was truncated (can be null)
     * @return the contents of the file, possibly truncated
     * @throws IOException if something goes wrong reading the file
     */
    public static String readTextFile(File file, int max, String ellipsis) throws IOException {
        InputStream input = new FileInputStream(file);
        try {
            long size = file.length();
            if (max > 0 || (size > 0 && max == 0)) {  // "head" mode: read the first N bytes
                if (size > 0 && (max == 0 || size < max)) max = (int) size;
                byte[] data = new byte[max + 1];
                int length = input.read(data);
                if (length <= 0) return "";
                if (length <= max) return new String(data, 0, length);
                if (ellipsis == null) return new String(data, 0, max);
                return new String(data, 0, max) + ellipsis;
            } else if (max < 0) {  // "tail" mode: keep the last N
                int len;
                boolean rolled = false;
                byte[] last = null, data = null;
                do {
                    if (last != null) rolled = true;
                    byte[] tmp = last; last = data; data = tmp;
                    if (data == null) data = new byte[-max];
                    len = input.read(data);
                } while (len == data.length);

                if (last == null && len <= 0) return "";
                if (last == null) return new String(data, 0, len);
                if (len > 0) {
                    rolled = true;
                    System.arraycopy(last, len, last, 0, last.length - len);
                    System.arraycopy(data, 0, last, last.length - len, len);
                }
                if (ellipsis == null || !rolled) return new String(last);
                return ellipsis + new String(last);
            } else {  // "cat" mode: size unknown, read it all in streaming fashion
                ByteArrayOutputStream contents = new ByteArrayOutputStream();
                int len;
                byte[] data = new byte[1024];
                do {
                    len = input.read(data);
                    if (len > 0) contents.write(data, 0, len);
                } while (len == data.length);
                return contents.toString();
            }
        } finally {
            input.close();
        }
    }
    
    /**
	 * 根据文件绝对路径获取文件名
	 * @param filePath
	 * @return
	 */
	public static String getFileName(String filePath ) {
		if( StringUtils.isEmpty(filePath) )	return "";
		return filePath.substring( filePath.lastIndexOf( File.separator )+1 );
	}
	
	public static boolean doesExisted(File file) {
		if (file != null && file.exists()) {
			return true;
		} else {
			return false;
		}

	}
	
	/**  
     * 将一个InputStream里面的数据写入到SD卡中  
     * @param path  
     * @param fileName  
     * @param input  
     * @return  
     */  
	public static File write2SDFromInput(String path, String fileName, InputStream input) {
		File file = null;
		OutputStream output = null;
		try {
			file = new File(path);
			if(!file.exists()) {
				file.mkdirs();
			}
			file = new File(path + fileName);
			if(!file.exists()) {
				file.createNewFile();
			}
			output = new FileOutputStream(file);
			byte[] buffer = new byte[4 * 1024];

			int length;
			while ((length = (input.read(buffer))) > 0) {
				output.write(buffer, 0, length);
			}

			output.flush();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				output.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return file;
	}
  
	public static String getFileExtend(String url) {
		if(TextUtils.isEmpty(url))return "";
		if(url.contains("/")) {
			return url.substring(url.lastIndexOf("/")+1, url.length());
		}
		return "";
	}
	
    public static boolean deleteFile(String fileName)
    {
        LogUtils.d("------>deleteFile + " + fileName);
        File file = new File(fileName);
        // 如果文件路径所对应的文件存在，并且是一个文件，则直接删除  
        if (file.exists() && file.isFile())
        {
            if (file.delete())
            {
                LogUtils.d("删除单个文件" + fileName + "成功！");
                return true;
            }
            else
            {
                LogUtils.d("删除单个文件" + fileName + "失败！");
                return false;
            }
        }
        else
        {
            LogUtils.d("删除单个文件失败：" + fileName + "不存在！");
            return false;
        }
    }
    

	/**
	 * 复制单个文件
	 * 
	 * @param oldPath
	 *            String 原文件路径 如：c:/fqf.txt
	 * @param newPath
	 *            String 复制后路径 如：f:/fqf.txt
	 * @return boolean
	 */
	public static void copyFile(String oldPath, String newPath) {
		try {
			int byteread = 0;
			File oldfile = new File(oldPath);
			if (oldfile.exists()) { // 文件存在时
				InputStream inStream = new FileInputStream(oldPath); // 读入原文件
				FileOutputStream fs = new FileOutputStream(newPath);
				byte[] buffer = new byte[1444];
				while ((byteread = inStream.read(buffer)) != -1) {
					fs.write(buffer, 0, byteread);
				}
				inStream.close();
				fs.close();
			}
		} catch (Exception e) {
//			System.out.println("复制单个文件操作出错");
			e.printStackTrace();

		}

	}

	/**
	 * 删除文件
	 * 
	 * @param filePathAndName
	 *            String 文件路径及名称 如c:/fqf.txt
	 * @return boolean
	 */
	public static void delFile(String filePathAndName) {
		try {
			String filePath = filePathAndName;
			filePath = filePath.toString();
			java.io.File myDelFile = new java.io.File(filePath);
			myDelFile.delete();

		} catch (Exception e) {
//			System.out.println("删除文件操作出错");
			e.printStackTrace();

		}

	}

	/**
	 * 移动文件到指定目录
	 * 
	 * @param oldPath
	 *            String 如：c:/fqf.txt
	 * @param newPath
	 *            String 如：d:/fqf.txt
	 */
	public static void moveFile(String oldPath, String newPath) {
		copyFile(oldPath, newPath);
		delFile(oldPath);
	}

	private static final String[] PIC_TYPE_ARY = {".jpg", ".jpeg", ".png", ".gif", ".bmp"};
    private static final String[] AUDIO_TYPE_ARY = {".mp3", ".wav", ".ogg", ".acc", ".wma"};

    public static String getSimpleFileType(String fileName) {
        String lowerName = fileName.toLowerCase();
        for (String s : PIC_TYPE_ARY) {
            if (lowerName.endsWith(s)) {
                return Constants.IAttachMentsType.TYPE_PIC;
            }
        }
        for (String s : AUDIO_TYPE_ARY) {
            if (lowerName.endsWith(s)) {
                return Constants.IAttachMentsType.TYPE_AUDIO;
            }
        }
        if (lowerName.endsWith(".mp4")) {
            return Constants.IAttachMentsType.TYPE_VIDEO;
        } else if (lowerName.endsWith(".txt")) { //txt word pdf excel类型的就传8文档类型
            return Constants.IAttachMentsType.TYPE_DOCUMENT;
        } else if (lowerName.endsWith(".pdf")) {
            return Constants.IAttachMentsType.TYPE_DOCUMENT;
        } else if (lowerName.endsWith(".doc") || lowerName.endsWith(".docx")) {
            return Constants.IAttachMentsType.TYPE_DOCUMENT;
        } else if (lowerName.endsWith(".xls") || lowerName.endsWith(".xlsx")) {
            return Constants.IAttachMentsType.TYPE_DOCUMENT;
        } else if (lowerName.endsWith(".apk")) {
            return Constants.IAttachMentsType.TYPE_APP;
        } else {
            return Constants.IAttachMentsType.TYPE_OTHERS;
        }
    }

    /**
     * 附件下载、预览功能
     * @param context
     * @param url 文件下载地址
     * @param sourceModel 文件来源类型，例如班级网盘、家校互动
     */
    public static void downAndViewAttachment(Context context, String url, int sourceModel) {
        // 家校互动附件下载前弹框提示
        ProgressDialogUtils.showProgressDialog(context.getString(R.string.attachment_downloading_tips), context, true);
        String preferenceName = "";
        String filePathPrefix = "";
        switch (sourceModel) {
            case Constants.ISourceModelPreferencesConst.ATTACHMENT_MODEL_CLOUDCLOUD:
                preferenceName = Constants.ISourceModelPreferencesConst.ATTACHMENT_PREFERENCE_NAME_CLOUDDISK;
                filePathPrefix = Utils.getSDPath() + Constants.FilePath;
                break;
            case Constants.ISourceModelPreferencesConst.ATTACHMENT_MODEL_JXHD:
                preferenceName = Constants.ISourceModelPreferencesConst.ATTACHMENT_PREFERENCE_NAME_JXHD;
                filePathPrefix = Utils.getSDPath() + Constants.FilePath;
                break;
        }
        SharedPreferences sp = context.getSharedPreferences(preferenceName, Activity.MODE_PRIVATE);
        String userId = BaseApplication.getInstance().getDefaultAccount().getId() + "";
        String[] tmp = url.split("/");
        String fileName = tmp[tmp.length - 1];
        String fileSaveId = fileName.split("\\.")[0]; // 文件名去掉后缀转化成文件唯一标识存储
        String filePath = filePathPrefix + "/" + userId;
        String fullPath = filePath + "/" + fileName;
        String key = userId + "_" + fileSaveId;
        long downId = sp.getLong(key, 0);

        if (downId == 0) {//没有下载过,开始下载
            downloadAttachment(context, url, fileName, "/EDU/" + preferenceName + "/" + userId, fullPath, key, preferenceName);
        } else {
            DownloadManager downloadManager = (DownloadManager) context.getSystemService(context.DOWNLOAD_SERVICE);
            DownloadManager.Query query = new DownloadManager.Query();
            query.setFilterById(downId);
            Cursor cursor = downloadManager.query(query);
            int state = 0;
            if (null != cursor && cursor.getCount() >= 1) {
                if (cursor.moveToFirst()) {
                    state = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));
                }
                cursor.close();
            }
            if (state == DownloadManager.STATUS_RUNNING) {//正在下载...
                Toast.makeText(context, "正在下载", Toast.LENGTH_SHORT).show();
                return;
            } else if (state == DownloadManager.STATUS_SUCCESSFUL) {//如果已经下载成功
                try {//判断文件是否存在，存在打开，不存在提示下载
                    File destDir = new File(filePath);
                    if (!destDir.exists()) {
                        destDir.mkdirs();
                    }
                    File file = new File(fullPath);
                    if (file.exists()) {
                        ProgressDialogUtils.dismissProgressBar();
                        Utils.openFile(context, file);
                    } else {
                        downloadAttachment(context, url, fileName, "/EDU/" + preferenceName + "/" + userId, fullPath, key, preferenceName);
                    }
                } catch (Exception e) {
                    ProgressDialogUtils.dismissProgressBar();
                    e.printStackTrace();
                }
                return;
            } else {
                downloadAttachment(context, url, fileName, "/EDU/" + preferenceName + "/" + userId, fullPath, key, preferenceName);
            }
        }
    }

    /**
     * 附件下载具体操作
     * @param context
     * @param fileUrl
     * @param fileName
     * @param filePath
     * @param fullPath
     * @param key
     * @param preferencesFileName
     */
    private static void downloadAttachment(Context context, String fileUrl, String fileName, String filePath,
                                           String fullPath, String key, String preferencesFileName) {
        try {
            DownloadManager downloadManager = (DownloadManager) context.getSystemService(context.DOWNLOAD_SERVICE);

            Uri uri = Uri.parse(fileUrl);
            DownloadManager.Request request = new DownloadManager.Request(uri);

            //设置允许使用的网络类型，这里是移动网络和wifi都可以
            request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE | DownloadManager.Request.NETWORK_WIFI);

            //禁止发出通知，既后台下载，如果要使用这一句必须声明一个权限：android.permission.DOWNLOAD_WITHOUT_NOTIFICATION
            //request.setShowRunningNotification(false);

            //不显示下载界面
            request.setVisibleInDownloadsUi(true);
                    /*设置下载后文件存放的位置,如果sdcard不可用，那么设置这个将报错，因此最好不设置如果sdcard可用，下载后的文件        在/mnt/sdcard/Android/data/packageName/files目录下面，如果sdcard不可用,设置了下面这个将报错，不设置，下载后的文件在/cache这个  目录下面*/
//                  request.setDestinationInExternalFilesDir(mContext, filePath, fileName);
            request.setDestinationInExternalPublicDir(filePath, fileName);
            long id = downloadManager.enqueue(request);

//            Toast.makeText(context, "文件正在下载，请在通知栏查看下载进度，文件保存在" + fullPath, Toast.LENGTH_LONG).show();
            // 把id保存好，在接收者里面要用，最好保存在Preferences里面
            SharedPreferences sp = context.getSharedPreferences(preferencesFileName, Activity.MODE_PRIVATE);
            SharedPreferences.Editor edit = sp.edit();
            edit.putLong(key, id);
            edit.commit();
        } catch (Exception e) {
            ProgressDialogUtils.dismissProgressBar();
            e.printStackTrace();
        }
    }

    /**
     * 直接打开DownloadManager下载结束后的文件
     * @param context
     * @param downId 在广播中取出下载任务的id
     */
    public static void openAttachmentAfterDownload(Context context, long downId) {

        ProgressDialogUtils.dismissProgressBar();
        DownloadManager downloadManager = (DownloadManager) context.getSystemService(context.DOWNLOAD_SERVICE);
        DownloadManager.Query query = new DownloadManager.Query();
        query.setFilterById(downId);
        Cursor cursor = downloadManager.query(query);
        if (null != cursor && cursor.getCount() >= 1) {
            if (cursor.moveToFirst()) {
                // 获取文件下载路径
                String filename = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME));
                // 如果文件名不为空，说明已经存在了
                try { // 判断文件是否存在，存在打开，不存在提示下载
                    File destDir = new File(filename);
                    if (!destDir.exists()) {
                        destDir.mkdirs();
                    }
                    File file = new File(filename);
                    if (file.exists()) {
                        Utils.openFile(context, file);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            cursor.close();
        }
    }

    @SuppressLint("NewApi")
    public static String getPath(final Context context, final Uri uri) {

        final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;

        if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
            if (isExternalStorageDocument(uri)) {
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];

                if ("primary".equalsIgnoreCase(type)) {
                    return Environment.getExternalStorageDirectory() + "/"
                            + split[1];
                }

                // TODO handle non-primary volumes
            }
            // DownloadsProvider
            else if (isDownloadsDocument(uri)) {

                final String id = DocumentsContract.getDocumentId(uri);
                final Uri contentUri = ContentUris.withAppendedId(
                        Uri.parse("content://downloads/public_downloads"),
                        Long.valueOf(id));

                return getDataColumn(context, contentUri, null, null);
            }
            // MediaProvider
            else if (isMediaDocument(uri)) {
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];

                Uri contentUri = null;
                if ("image".equals(type)) {
                    contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
                } else if ("video".equals(type)) {
                    contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
                } else if ("audio".equals(type)) {
                    contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
                }

                final String selection = "_id=?";
                final String[] selectionArgs = new String[] { split[1] };

                return getDataColumn(context, contentUri, selection,
                        selectionArgs);
            }
        }
        // MediaStore (and general)
        else if ("content".equalsIgnoreCase(uri.getScheme())) {

            // Return the remote address
            if (isGooglePhotosUri(uri))
                return uri.getLastPathSegment();

            return getDataColumn(context, uri, null, null);
        }
        // File
        else if ("file".equalsIgnoreCase(uri.getScheme())) {
            return uri.getPath();
        }

        return null;
    }

    /**
     * Get the value of the data column for this Uri. This is useful for
     * MediaStore Uris, and other file-based ContentProviders.
     *
     * @param context
     *            The context.
     * @param uri
     *            The Uri to query.
     * @param selection
     *            (Optional) Filter used in the query.
     * @param selectionArgs
     *            (Optional) Selection arguments used in the query.
     * @return The value of the _data column, which is typically a file path.
     */
    public static String getDataColumn(Context context, Uri uri,
                                       String selection, String[] selectionArgs) {

        Cursor cursor = null;
        final String column = "_data";
        final String[] projection = { column };

        try {
            cursor = context.getContentResolver().query(uri, projection,
                    selection, selectionArgs, null);
            if (cursor != null && cursor.moveToFirst()) {
                final int index = cursor.getColumnIndexOrThrow(column);
                return cursor.getString(index);
            }
        } finally {
            if (cursor != null)
                cursor.close();
        }
        return null;
    }

    /**
     * @param uri
     *            The Uri to check.
     * @return Whether the Uri authority is ExternalStorageProvider.
     */
    public static boolean isExternalStorageDocument(Uri uri) {
        return "com.android.externalstorage.documents".equals(uri
                .getAuthority());
    }

    /**
     * @param uri
     *            The Uri to check.
     * @return Whether the Uri authority is DownloadsProvider.
     */
    public static boolean isDownloadsDocument(Uri uri) {
        return "com.android.providers.downloads.documents".equals(uri
                .getAuthority());
    }

    /**
     * @param uri
     *            The Uri to check.
     * @return Whether the Uri authority is MediaProvider.
     */
    public static boolean isMediaDocument(Uri uri) {
        return "com.android.providers.media.documents".equals(uri
                .getAuthority());
    }

    /**
     * @param uri
     *            The Uri to check.
     * @return Whether the Uri authority is Google Photos.
     */
    public static boolean isGooglePhotosUri(Uri uri) {
        return "com.google.android.apps.photos.content".equals(uri
                .getAuthority());
    }
}
